package com.crd.zk;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.imps.CuratorFrameworkState;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.RetryNTimes;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import static org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent.Type.CHILD_UPDATED;

public class MyDataSource  implements DataSource {


    private Map<String, String> configMap = new HashMap<>();//当前获取到的配置信息

    private static final String CONFIG_PREFIX = "/CONFIG";//监听的路径

    private final CuratorFramework zkClient;//zookeeper对象

    private volatile ComboPooledDataSource datasource;//链接池

    //建立数据源
    public static MyDataSource create(String zookeeperAddress) throws Exception {
        return new MyDataSource(CuratorFrameworkFactory.newClient(zookeeperAddress, new RetryNTimes(3, 1000)));
    }


    //自动生成
    public MyDataSource(CuratorFramework zkClient) {
        this.zkClient = zkClient;
        //启动zookeeper客户端
        if (!zkClient.getState().equals(CuratorFrameworkState.STARTED)) {
            zkClient.start();
        }

        try {
            // 获取当前数据源信息
            getDatasourceConfig();

            // 进行初始化真实的数据源
            initDataSource();

            // 进行启动监听
            startListener();
        } catch (Exception e) {
            throw new IllegalStateException("启动动态代理数据源失败！", e);
        }
    }

    public void changeDatasourceConfig(String name) throws Exception {
        zkClient.setData().forPath(CONFIG_PREFIX+"/username",name.getBytes());
    }

    private void getDatasourceConfig() throws Exception {
        List<String> childrenNames = zkClient.getChildren().forPath(CONFIG_PREFIX);
        for (String childrenName : childrenNames) {
            String value = new String(zkClient.getData().forPath(CONFIG_PREFIX + "/" + childrenName));
            configMap.put(childrenName,value);
        }
    }


    private void initDataSource() throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();

        System.out.println("driverClassName:"+configMap.get("driverClassName")+";dbJDBCUrl："+configMap.get("dbJDBCUrl")+";username:"+configMap.get("username")+";password:"+configMap.get("password"));
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://linux123:3306/azkaban?characterEncoding=utf-8&useSSL=false");
        dataSource.setUser(configMap.get("username"));
        dataSource.setPassword("12345678");

        // 将数据源切换为新的数据源
        this.datasource = dataSource;
    }


    private void startListener() throws Exception {
        PathChildrenCache watcher = new PathChildrenCache(zkClient, CONFIG_PREFIX, true);
        watcher.getListenable().addListener(new PathChildrenCacheListener() {

            public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent event) throws Exception {
                if (event.getType() != CHILD_UPDATED) {
                    return;
                }
                System.out.println("检测到数据源信息变更:" + new String(event.getData().getData()));

                // 重置配置信息
                getDatasourceConfig();

                // 获取当前系统中的数据源
                final ComboPooledDataSource currentDatasource = MyDataSource.this.datasource;

                // 进行重置数据源
                initDataSource();

                // 关闭系统中遗留的数据源信息
                if (currentDatasource != null) {
                    currentDatasource.close();
                }
            }
        });
        watcher.start();
        System.out.println("完成对数据源的监听操作");
    }






    @Override
    public Connection getConnection() throws SQLException {
        return datasource.getConnection();
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return datasource.getConnection(username, password);
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }
}
